﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Runtime.Serialization.Formatters.Binary;
using MMOShared.Packets;
using MMOShared;

namespace MMOMasterServer
{
    public class LoginAcceptor
    {
        public static void ProcessLogin(TcpClient client,MasterServerDB db, MasterVersionList versions)
        {
            NetworkStream stream = client.GetStream();
            BinaryFormatter read = new BinaryFormatter();
            bool sendServerList = false;
            bool startUpdate = false;
            Console.WriteLine("Waiting for authentication details");
            while (true)
            {
                if (client.Connected)
                {
                    if (stream.DataAvailable)
                    {
                        object obj = read.Deserialize(stream);
                        if (obj is MMOShared.LoginDetails)
                        {
                            Console.WriteLine("Details received");
                            MMOShared.LoginDetails det = obj as MMOShared.LoginDetails;
                            if (db.loginAccount(det.Username, det.Password))
                            {
                                Console.WriteLine("\tLogin Success!");
                                //send connection success
                                sendServerList = true;
                                stream.WriteByte(1);
                                stream.Flush();
                                Console.WriteLine("\tSetting user to logged in");
                                db.setLoggedIn(det.Username);
                                continue;
                            }
                            else
                            {
                                Console.WriteLine("\tLogin Failed!");
                                //send connection failed
                                stream.WriteByte(0);
                                stream.Flush();
                                return;
                            }
                        }
                        else
                        {
                            Console.WriteLine("Object was not login info");
                        }
                    }
                    if (sendServerList)
                    {
                        Console.WriteLine("Sending server list");
                        MMOShared.ServerList list = db.getServers();
                        read.Serialize(stream, list);
                        stream.Flush();
                        //don't send it again
                        sendServerList = false;
                        startUpdate = true;
                    }
                    if (startUpdate)
                    {
                        WaitForVersionRequestAndDownload(client, db, versions);
                    }
                }
                else
                {
                    Console.WriteLine("User disconnected, killing thread");
                    //user disconnected so yeah
                    return;
                }
            }
        }

        private static void WaitForVersionRequestAndDownload(TcpClient client,MasterServerDB db, MasterVersionList versions)
        {
            Console.WriteLine("Begining to update client");
            NetworkStream stream = client.GetStream();
            BinaryFormatter bf = new BinaryFormatter();
            Console.WriteLine("Waiting for update request");
            while (true)
            {
                //Wait for version requests and act accordingly
                if (client.Connected && stream.DataAvailable)
                {
                    object rec = bf.Deserialize(stream);
                    if (rec is UpdateRequest)
                    {
                        UpdateRequest ur = (UpdateRequest)rec;
                        if (ur.CurrentAction == UpdateRequest.Action.UPDATE_QUERY)
                        {
                            //Send update versions
                            Console.WriteLine("Sending available updates");
                            VersionsAvailable va = new VersionsAvailable(versions.GetLoadedVersionNumbers());
                            bf.Serialize(stream, va);
                            stream.Flush();
                        }
                        else
                        {
                            //Send header
                            long size = 0;
                            int nFiles = 0; int nPieces = 0;
                            Console.WriteLine("Sending update header");
                            db.GetUpdateInfo(ur.Version, out size, out nFiles, out nPieces);
                            UpdateHeader h = new UpdateHeader(size, nFiles, nPieces);
                            bf.Serialize(stream, h);
                            stream.Flush();

                            //Send ResourceManager
                            Console.WriteLine("Sending ResourceManager");
                            ResourceManager r = ResourceManager.Load("Updates\\" + ur.Version + "\\res_man.res");
                            if (r.IsLoaded)
                            {
                                bf.Serialize(stream, r);
                                stream.Flush();
                            }

                            //Send pieces
                            int i = 1;
                            Console.WriteLine("Starting update transfer");
                            List<FileUpdatePiece> p = db.RequestUpdateFileList(ur.Version);
                            foreach (FileUpdatePiece f in p)
                            {
                                Console.WriteLine("Sending piece " + i);
                                bf.Serialize(stream, f);
                                stream.Flush();
                                i++;
                            }

                            //end loop
                            Console.WriteLine("Done transfering update");
                            return;
                        }
                    }
                }
            }

        }
    }
}
